#import "DemoDiagram.h"
#import "DiagramCell.h"

@implementation DemoDiagram

- initFrame:(NXRect *)r
{
	[super initFrame:r];
	
	/* Compute view limits for later use. */
	minX=bounds.origin.x;
	maxX=minX+bounds.size.width-1.0;
	minY=bounds.origin.y;
	maxY=minY+bounds.size.height-1.0;
	
	itemList=[[List alloc] initCount:10];  //List of graphic items in the diagram
	[self setClipping:NO];			//Faster, and we'll be careful
	return self;
}

- setBackground:(NXImage *)anImage
{
	bgImage=anImage;
	return self;
}

/* Drawing the view consists simply of compositing the background, then compositing
each of the graphic items. */

- drawSelf:(NXRect *)rect :(int)c
{
	int i;
	[bgImage composite:NX_COPY toPoint:&bounds.origin];
	for (i=0; i<[itemList count]; i++){
		[[itemList objectAt:i] drawSelf];
	}
	return self;
}

- addItem:item
{
	[itemList addObject:item];
	[self display];
	return self;
}

/* When the mouse goes down, search the item list, from top to bottom, for the first
object answering self to the mouseHit request.  That becomes the moused object. */

- mouseDownAction:(NXPoint *)location
{
	id item;
	int i;
	mousedObject=nil;
	
	for (i=[itemList count]-1; i>=0; i--){
		item=[itemList objectAt:i];
		if([item mouseHit:location]){
			mousedObject=item;
			oldMouse=*location;		//save first mouse location
			break;
		}
	}
	[self lockFocus];			//prepare to draw while dragging
	return self;
}

/* When dragging, ask each item to draw its intersection with the dirty rectangle. */

- mouseDraggedAction:(NXPoint *)newMouse
{
	int i;
	NXPoint mouseLoc;		//location of the mouse cursor;
	float dx,dy;			//relative x and y changes;
	NXRect dirtyRect,newRect;
	
	if(!mousedObject)return self;	// If no mousehit in mouseDown
	
	/* Save rectangle before moving as initial dirty rect */
	[mousedObject getFrame:&dirtyRect];

	/* This is the new location of the mouse */
	mouseLoc=*newMouse;
	
	/* First, constrain mouse point to appear to be in the view */
	if(mouseLoc.x > maxX)mouseLoc.x = maxX;
	if(mouseLoc.x < minX)mouseLoc.x = minX;
	if(mouseLoc.y > maxY)mouseLoc.y = maxY;
	if(mouseLoc.y < minY)mouseLoc.y = minY;
	
	/* Now, find effective change in x and y */
	dx=mouseLoc.x-oldMouse.x;
	dy=mouseLoc.y-oldMouse.y;
		
	/* Save mouse location for next time around */
	oldMouse=mouseLoc;
	
	/* Finally, ask item to move as far as it can within the bounds of the view. */
	[mousedObject moveBy:dx :dy inViewRect:&bounds];
	
	/* Find out where it ended up */
	[mousedObject getFrame:&newRect];
	
	/* Compute dirty rectangle that needs redrawing */
	NXUnionRect(&newRect,&dirtyRect);  //replaces second rect with union
	
	/* Now time to draw in the view */
	
		/* Erase dirty rectangle in the view*/
		[bgImage composite:NX_COPY fromRect:&dirtyRect toPoint:&dirtyRect.origin];
	
		/* For each object, redraw the portion that intersects the dirty rect. */
		for (i=0; i<[itemList count]; i++)
			[[itemList objectAt:i] drawInDirtyRect:&dirtyRect];

	[window flushWindow];
	return self;
}

- mouseUpAction:(NXPoint *)location
{
	[self unlockFocus];
	return self;
}

@end